package com.sky.service.impl;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sky.constant.StatusConstant;
import com.sky.dto.SetmealDTO;
import com.sky.dto.SetmealPageQueryDTO;
import com.sky.dto.UserThredDTO;
import com.sky.entity.Category;
import com.sky.entity.Dish;
import com.sky.entity.Setmeal;
import com.sky.entity.SetmealDish;
import com.sky.exception.BaseException;
import com.sky.mapper.SetmealDishMapper;
import com.sky.mapper.SetmealMapper;
import com.sky.result.Result;
import com.sky.service.CategoryService;
import com.sky.service.IDishService;
import com.sky.service.ISetmealDishService;
import com.sky.service.ISetmealService;
import com.sky.utils.UserThreadUtil;
import com.sky.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 套餐 服务实现类
 * </p>
 *
 * @author xieminghui
 * @since 2023-11-16
 */
@Slf4j
@Service
public class SetmealServiceImpl extends ServiceImpl<SetmealMapper, Setmeal> implements ISetmealService {
    @Resource
    private CategoryService categoryService;

    @Resource
    private ISetmealDishService iSetmealDishService;
    @Resource
    private SetmealDishMapper setmealDishMapper;

    /**
     * 分页查询套餐
     *
     * @author: XieMingHui
     * @date: 23/11/20 14:39:44
     * @param: [setmealPageQueryDTO]
     * @return: java.util.List<com.sky.vo.SetmealVO>
     **/
    @Override
    public Result<SetmealPageVO> findPage(SetmealPageQueryDTO setmealPageQueryDTO) {
        // 先查套餐信息
        Page<Setmeal> setmealPage = getSetmealPage(setmealPageQueryDTO);
        List<Setmeal> records = setmealPage.getRecords();
        // // 封装到VO,获取分类id查询分类
        List<SetmealALLVO> list = new ArrayList<>(records.size());
        for (Setmeal setmeal : records) {
            // 封装属性到VO
            list.add(BeanUtil.toBean(setmeal, SetmealALLVO.class));
        }
        // 查询分类名称
        findCategory(list);
        log.info("查询分类表,并封装到对应的套餐内");
        return Result.success(new SetmealPageVO(list, setmealPage.getTotal()));
    }

    /**
     * 新增套餐
     *
     * @author: XieMingHui
     * @date: 23/11/20 18:25:14
     * @param: [setmealDTO]
     * @return: com.sky.result.Result<java.lang.String>
     **/
    @Override
    @Transactional
    public Result<String> saveSetmeal(SetmealDTO setmealDTO) {
        log.info("套餐分类id:{}", setmealDTO.getCategoryId());
        UserThredDTO userThredDTO = UserThreadUtil.getThread();
        Setmeal setmeal = BeanUtil.toBean(setmealDTO, Setmeal.class);
        LocalDateTime now = LocalDateTime.now();
        Long id = userThredDTO.getId();
        setmeal.setCreateTime(now);
        setmeal.setCreateUser(id);
        setmeal.setUpdateTime(now);
        setmeal.setUpdateUser(id);
        save(setmeal);
        List<SetmealDish> setmealDishes = setmealDTO.getSetmealDishes();
        for (SetmealDish setmealDish : setmealDishes) {
            setmealDish.setSetmealId(setmeal.getId());
        }
        iSetmealDishService.saveBatch(setmealDishes);
        return Result.success("新增成功");
    }

    /**
     * 根据id查询套餐详情,用于修改回显
     *
     * @author: XieMingHui
     * @date: 23/11/20 19:00:00
     * @param: [id]
     * @return: 套餐详情, 包含菜品信息
     **/
    @Override
    public Result<SetmealVO> findById(Long id) {
        Setmeal setmeal = getById(id);
        SetmealVO setmealVO = BeanUtil.toBean(setmeal, SetmealVO.class);
        // 根据套餐id查询关系表,得到关系表对象
        List<SetmealDish> list = iSetmealDishService.lambdaQuery()
                .eq(SetmealDish::getSetmealId, id)
                .list();
        setmealVO.setSetmealDishes(list);
        log.info("修改回显的数据:{}", setmealVO);
        return Result.success(setmealVO);
    }

    /**
     * 修改套餐
     *
     * @author: XieMingHui
     * @date: 23/11/20 19:00:00
     * @param: [id]
     * @return: 套餐详情, 包含菜品信息
     **/
    @Override
    @Transactional
    public Result<String> updateSetmeal(SetmealDTO setmealDTO) {
        log.info("修改套餐的信息:{}", setmealDTO);
        Setmeal setmeal = BeanUtil.toBean(setmealDTO, Setmeal.class);
        updateById(setmeal);
        // 修改关系表
        QueryWrapper<SetmealDish> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(SetmealDish::getSetmealId, setmealDTO.getId());
        // 先删除,再新增
        iSetmealDishService.remove(wrapper);
        List<SetmealDish> setmealDishes = setmealDTO.getSetmealDishes();
        for (SetmealDish setmealDish : setmealDishes) {
            setmealDish.setSetmealId(setmealDTO.getId());
        }
        iSetmealDishService.saveBatch(setmealDishes);
        return Result.success("更新成功");
    }

    /**
     * 修改售卖状态
     *
     * @author: XieMingHui
     * @date: 23/11/20 19:00:00
     * @param: [id]
     * @return: 套餐详情, 包含菜品信息
     **/
    @Override
    @Transactional
    public Result<String> updateStatus(Integer status, Long id) {
        lambdaQuery().eq(id != null, Setmeal::getId, id);
        UpdateWrapper<Setmeal> wrapper = new UpdateWrapper<>();
        wrapper.lambda().eq(id != null, Setmeal::getId, id)
                .set(status != null, Setmeal::getStatus, status);
        update(wrapper);
        return Result.success("操作成功");
    }

    /**
     * 删除套餐
     *
     * @author: XieMingHui
     * @date: 23/11/20 19:00:00
     * @param: [id]
     * @return: 操作结果
     **/
    @Override
    @Transactional
    public Result<String> DeleteStatus(List<Long> ids) {
        removeByIds(ids);
        QueryWrapper<SetmealDish> wrapper = new QueryWrapper<>();
        wrapper.lambda().in(SetmealDish::getSetmealId, ids);
        iSetmealDishService.remove(wrapper);
        return Result.success("操作成功");
    }

    /**
     * 条件查询
     *
     * @param categoryId 分类id
     * @return 套餐
     */
    @Override
    public List<Setmeal> findByid(Long categoryId) {
        List<Setmeal> list = lambdaQuery()
                .eq(categoryId != null, Setmeal::getCategoryId, categoryId)
                .eq(Setmeal::getStatus, StatusConstant.ENABLE)
                .list();
        return list;
    }
    /**
     * 根据套餐id查询菜品部分信息
     * @author: XieMingHui
     * @param: [id]
     * @return: 菜品名,图,价格,份数,描述
     **/
    @Override
    public List<DishItemVO> getDishItemById(Long id) {
        if(id==null){
            throw new BaseException("没有这个套餐");
        }
        return setmealDishMapper.getDishItemBySetmealId(id);
    }

    // 查询分类
    private void findCategory(List<SetmealALLVO> list) {
        Map<Long, String> categoryMap = categoryService.list().stream()
                .collect(Collectors.toMap(Category::getId, Category::getName));
        // 遍历菜品集合
        for (SetmealALLVO setmealVO : list) {
            Long categoryId = setmealVO.getCategoryId();
            // 根据分类id查找集合中是否有对应的分类
            String name = categoryMap.get(categoryId);
            if (StrUtil.isNotBlank(name)) {
                // 有,封装到Vo
                setmealVO.setCategoryName(name);
            }
        }
    }

    // 分页查询
    private Page<Setmeal> getSetmealPage(SetmealPageQueryDTO setmealPageQueryDTO) {
        String name = setmealPageQueryDTO.getName();
        Integer status = setmealPageQueryDTO.getStatus();
        Integer categoryId = setmealPageQueryDTO.getCategoryId();
        Integer page = setmealPageQueryDTO.getPage();
        Integer pageSize = setmealPageQueryDTO.getPageSize();
        if (page == null || pageSize == null) {
            page = 1;
            pageSize = 10;
        }
        return lambdaQuery()
                .eq(status != null, Setmeal::getStatus, status)
                .eq(categoryId != null, Setmeal::getCategoryId, categoryId)
                .like(StrUtil.isNotBlank(name), Setmeal::getName, name)
                .page(new Page<>(page, pageSize));
    }
}
